/*
qnettest - Qt4 application for testing network performance
Copyright (C) 2007  Pyry Haulos

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include <QtCore>
#include "nettest.hpp"
#include "tcpserver.hpp"
#include "tcpclient.hpp"
#include "tcpproto.hpp"

NetTest::NetTest(QStringList * arguments)
{
	die = true;
	client = false;
	server = false;
	
	out = new QTextStream(stdout);
	// out->setCodec(QTextCodec::codecForName("UTF-8"));
	out->setRealNumberPrecision(2);
	out->setRealNumberNotation(QTextStream::FixedNotation);

	port = 12345;
	send_bytes = 1024;
	recv_bytes = 16;
	simult_num = 10;
	time = 1000;
	interval = 10;

	QString app = arguments->at(0);

	for (QStringList::Iterator i = arguments->begin(); i != arguments->end(); ++i) {
		if (*i == "--help")
			break;
		else if (*i == "--server") {
			if (client) {
				die = true;
				break;
			}

			server = true;
			die = false;
		} else if (*i == "--client") {
			if (server) {
				die = true;
				break;
			}

			++i;

			if (i == arguments->end())
				break;

			address = *i;

			client = true;
			die = false;
		} else if (*i == "--port") {
			if (!iterNextUint16(&i, arguments->end(), &port))
				die = true;
		} else if (*i == "--send") {
			if (!iterNextInt32(&i, arguments->end(), &send_bytes))
				die = true;

			if (send_bytes < TcpProto::sendHeaderSize())
				die = true;
		} else if (*i == "--recieve") {
			if (!iterNextInt32(&i, arguments->end(), &recv_bytes))
				die = true;

			if (recv_bytes < TcpProto::recvHeaderSize())
				die = true;
		} else if (*i == "--simultaneous") {
			if (!iterNextInt32(&i, arguments->end(), &simult_num))
				die = true;

			if (simult_num < 1)
				die = true;
		} else if (*i == "--time") {
			if (!iterNextInt32(&i, arguments->end(), &time))
				die = true;

			if (time < 0)
				die = true;
		} else if (*i == "--interval") {
			if (!iterNextInt32(&i, arguments->end(), &interval))
				die = true;

			if (interval < 1)
				die = true;
		}
	}

	if (die)
		showHelp(app);
}

bool NetTest::iterNextInt32(QStringList::Iterator * i, QStringList::Iterator end, qint32 * num)
{
	++(*i);

	if (*i == end)
		return false;

	bool ok = true;

	*num = (*i)->toInt(&ok);

	if (!ok)
		return false;
	return true;
}

bool NetTest::iterNextUint16(QStringList::Iterator * i, QStringList::Iterator end, quint16 * num)
{
	++(*i);

	if (*i == end)
		return false;

	bool ok = true;

	*num = (*i)->toUShort(&ok);

	if (!ok)
		return false;
	return true;
}

NetTest::~NetTest()
{
	// cleanup?
}

void NetTest::showHelp(QString app)
{
	*out << "Usage: " << app << endl;
	*out << "  --help                  show this help" << endl;
	*out << "  --server                start as server" << endl;
	*out << "  --client [address]      test against server" << endl;
	*out << "  --port [port]           server port, default is 12345" << endl;
	*out << "  --simultaneous [count]  number of simultaneous connections, default is 10" << endl;
	*out << "  --send [bytes]          bytes to send, default is 1024" << endl;
	*out << "  --recieve [bytes]       bytes to recieve, default is 16" << endl;
	*out << "  --time [msecs]          time in milliseconds, default is 1000" << endl;
	*out << "  --interval [msecs]      time in milliseconds, default is 10" << endl;
}

bool NetTest::start()
{
	if (die)
		return false;

	if (server) {
		TcpServer *server = new TcpServer;

		if (!server->listen(QHostAddress::Any, port)) {
			*out << "NetTest::start(): can't start server: " << server->errorString() << endl;
			return false;
		}
		return true;
	} else if (client) {
		args = new TcpClientArgs;

		args->address = address;
		args->port = port;
		args->send_bytes = send_bytes;
		args->recv_bytes = recv_bytes;
		args->simult_num = simult_num;
		args->time = time;
		args->interval = interval;
		args->outStream = out;

		tcpclient = new TcpClient(args);

		connect(tcpclient, SIGNAL(finished()), this, SLOT(clientFinished()));

		tcpclient->start();
		return true;
	}

	return false;
}

void NetTest::clientFinished()
{
	delete tcpclient;
	delete args;
	emit finished();
}
